package com.hongxin.doc.api.controller;

import com.hongxin.doc.api.dto.UserRequest;
import com.hongxin.doc.common.onlyoffice.token.edit.EditProperties;
import com.hongxin.doc.common.onlyoffice.token.edit.UserProperties;
import com.hongxin.doc.common.response.Result;
import com.hongxin.doc.common.util.JsonUtil;
import com.hongxin.doc.common.util.JwtUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

@Tag(name = "文档服务")
@Slf4j
@RestController
@RequestMapping("/document/api/")
public class DocumentController {

    @Value("${onlyoffice.document.root.dir}")
    private String documentDir;

    @Value("${onlyoffice.jwt.secret}")
    private String jwtSecret;

    @Operation(summary = "创建资源", description = "创建文档资源")
    @PostMapping("/create")
    public Result create(@RequestBody UserRequest user) {
        // 确保目录存在
        File dir = new File(this.documentDir);
        if (!dir.exists()) {
            boolean created = dir.mkdirs();
            if (!created) {
                log.error("message: Failed to create directory: '{}'", this.documentDir);
                return Result.error("创建目录失败");
            }
        }

        // 使用 UUID 生成唯一的文档 ID
        String docId = UUID.randomUUID().toString();
        String fileName = docId + "." + user.getDocType();
        String filePath = this.documentDir + "/" + fileName;

        // 创建空的文件
        Workbook workbook = null;
        try {
            switch (user.getDocType()) {
                case "docx" -> Files.createFile(Paths.get(filePath));
                case "xlsx" -> {
                    workbook = new XSSFWorkbook(); // 创建 .xlsx 格式的工作簿
                    workbook.createSheet("Sheet1");
                    FileOutputStream fileOut = new FileOutputStream(filePath);
                    workbook.write(fileOut); // 写入 Excel 文件
                }
            }


            // 编辑文档参数
            String key = user.getDocKey();
            String docTitle = user.getDocKey() + "." + user.getDocType();
            String docUrl = "http://172.30.23.105:8080/documents/" + docTitle;
            String callbackUrl = "http://172.30.23.105:6080/document/api/callback";
            UserProperties userProperties = new UserProperties("方案解决部", user.getId().toString(), user.getName());
            EditProperties editProperties = new EditProperties(user.getDocType(), key, docTitle, docUrl, callbackUrl, userProperties);

            // 生成jwt token
            String editPropertiesJson = JsonUtil.getJson(editProperties);
            System.out.println(editPropertiesJson);
            String token = JwtUtil.generateToken(editPropertiesJson, jwtSecret);

            Map<String, Object> result = new HashMap<>();
            result.put("token", token);
            result.put("config", editProperties);

            return Result.success(result);
        } catch (Exception e) {
            return Result.error("失败");
        } finally {
            if (null != workbook) {
                try {
                    workbook.close(); // 关闭工作簿，释放资源
                } catch (IOException e) {
                    System.out.println(e);
                }
            }
        }

    }

    private void createExcel(String filePath) {
// 创建一个新的空 Excel 文件
        Workbook workbook = new XSSFWorkbook(); // 创建 .xlsx 格式的工作簿
        workbook.createSheet("Sheet1");

        // 写入文件
        try (FileOutputStream fileOut = new FileOutputStream("empty_excel.xlsx")) {
            workbook.write(fileOut); // 写入 Excel 文件
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                workbook.close(); // 关闭工作簿，释放资源
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 回调相关文档：
     *      https://api.onlyoffice.com/docs/docs-api/usage-api/callback-handler/
     * status:
     *     定义用户对文档执行操作时收到的对象数组。类型字段值可以具有以下值：
     *      0-用户断开文档共同编辑连接；
     *      1-新用户连接到文档共同编辑；
     *      2 – 用户点击强制保存按钮。
     *      3 - 每次提交表单时都会执行强制保存请求（例如，单击“完成并提交”按钮）。
     *  url:
     *      定义要保存在文档存储服务中的已编辑文档的链接，已经修改过的文档缓存链接。仅当状态值等于2、3、6或7时，此链接才存在。
     *  userid: 字段值是用户标识符。
     *  actions:
     *      type,定义用户对文档执行操作时收到的对象数组。类型字段值可以具有以下值：
     *         0-用户断开文档共同编辑连接；
     *         1-新用户连接到文档共同编辑；
     *         2 – 用户点击强制保存按钮。
     *     userid,字段值是用户标识符。
     * 类型：对象数组
     * 类型：对象数组
     * 修改
     * {
     *     "key": "4d2b0926-716e-49e2-ba3e-12238afedaf6",
     *     "status": 2,
     *     "url": "http://172.30.23.105/cache/files/data/4d2b0926-716e-49e2-ba3e-12238afedaf6_6887/output.docx/output.docx?md5=7kdQ7qlxnrBEkrTLZsTdxA&expires=1734079899&shardkey=4d2b0926-716e-49e2-ba3e-12238afedaf6&filename=output.docx",
     *     "changesurl": "http://172.30.23.105/cache/files/data/4d2b0926-716e-49e2-ba3e-12238afedaf6_6887/changes.zip/changes.zip?md5=2MiuSrjXsOLbJyP-KnajLQ&expires=1734079899&shardkey=4d2b0926-716e-49e2-ba3e-12238afedaf6&filename=changes.zip",
     *     "history": {
     *         "serverVersion": "8.2.2",
     *         "changes": [
     *             {
     *                 "documentSha256": "5eabb07aa6c7ad831b8834064b7698952508963864e7b3b66024cccf472a2e4b",
     *                 "created": "2024-12-13 08:25:50",
     *                 "user": {
     *                     "id": "1",
     *                     "name": "方案解决部 董亮之"
     *                 }
     *             }
     *         ]
     *     },
     *     "users": [
     *         "1"
     *     ],
     *     "actions": [
     *         {
     *             "type": 0,
     *             "userid": "1"
     *         }
     *     ],
     *     "lastsave": "2024-12-13T08:30:17.000Z",
     *     "notmodified": false,
     *     "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiI0ZDJiMDkyNi03MTZlLTQ5ZTItYmEzZS0xMjIzOGFmZWRhZjYiLCJzdGF0dXMiOjIsInVybCI6Imh0dHA6Ly8xNzIuMzAuMjMuMTA1L2NhY2hlL2ZpbGVzL2RhdGEvNGQyYjA5MjYtNzE2ZS00OWUyLWJhM2UtMTIyMzhhZmVkYWY2XzY4ODcvb3V0cHV0LmRvY3gvb3V0cHV0LmRvY3g_bWQ1PTdrZFE3cWx4bnJCRWtyVExac1RkeEEmZXhwaXJlcz0xNzM0MDc5ODk5JnNoYXJka2V5PTRkMmIwOTI2LTcxNmUtNDllMi1iYTNlLTEyMjM4YWZlZGFmNiZmaWxlbmFtZT1vdXRwdXQuZG9jeCIsImNoYW5nZXN1cmwiOiJodHRwOi8vMTcyLjMwLjIzLjEwNS9jYWNoZS9maWxlcy9kYXRhLzRkMmIwOTI2LTcxNmUtNDllMi1iYTNlLTEyMjM4YWZlZGFmNl82ODg3L2NoYW5nZXMuemlwL2NoYW5nZXMuemlwP21kNT0yTWl1U3JqWHNPTGJKeVAtS25hakxRJmV4cGlyZXM9MTczNDA3OTg5OSZzaGFyZGtleT00ZDJiMDkyNi03MTZlLTQ5ZTItYmEzZS0xMjIzOGFmZWRhZjYmZmlsZW5hbWU9Y2hhbmdlcy56aXAiLCJoaXN0b3J5Ijp7InNlcnZlclZlcnNpb24iOiI4LjIuMiIsImNoYW5nZXMiOlt7ImRvY3VtZW50U2hhMjU2IjoiNWVhYmIwN2FhNmM3YWQ4MzFiODgzNDA2NGI3Njk4OTUyNTA4OTYzODY0ZTdiM2I2NjAyNGNjY2Y0NzJhMmU0YiIsImNyZWF0ZWQiOiIyMDI0LTEyLTEzIDA4OjI1OjUwIiwidXNlciI6eyJpZCI6IjEiLCJuYW1lIjoi5pa55qGI6Kej5Yaz6YOowqDokaPkuq7kuYsifX1dfSwidXNlcnMiOlsiMSJdLCJhY3Rpb25zIjpbeyJ0eXBlIjowLCJ1c2VyaWQiOiIxIn1dLCJsYXN0c2F2ZSI6IjIwMjQtMTItMTNUMDg6MzA6MTcuMDAwWiIsIm5vdG1vZGlmaWVkIjpmYWxzZSwiZmlsZXR5cGUiOiJkb2N4IiwiaWF0IjoxNzM0MDc4OTk4LCJleHAiOjE3MzQwNzkyOTh9.-nC8d-uf987PfFor1fOMbIFivqf2rrHU4--NMucWw7U",
     *     "filetype": "docx"
     * }
     * @param payload onlyoffice服务器发送过来的参数
     * @return Map
     */
    @PostMapping("/callback")
    public Map<String, String> handleCallback(@RequestBody Map<String, Object> payload) {
        int status = Integer.parseInt(payload.getOrDefault("status", "-99").toString());
        switch (status) {
            // 保存文件。2: 文档已准备好保存；3: 每次提交表单时都会执行强制保存请求；
            case 2, 3 -> this.save(payload);
        }

        // 将onlyoffice服务器发送过来的参数记录到日志中
        log.info("payload: {}", JsonUtil.getJson(payload));

        Map<String, String> result = new HashMap<>();
        result.put("error", "0");
        return result;
    }

    /**
     * 保存文件
     * @param payload onlyoffice服务器发送过来的参数
     */
    private void save(Map<String, Object> payload) {
        String url = payload.getOrDefault("url", "").toString();
        if (StringUtils.isBlank(url)) {
            log.error("message: URL为空，无法打开文件");
            return;
        }

        InputStream inputStream = null;
        FileOutputStream outputStream = null;

        try {
            // 连接远程文件资源
            URI uri = new URI(url);
            URL fileUrl = uri.toURL();
            HttpURLConnection httpConn = (HttpURLConnection) fileUrl.openConnection();
            httpConn.setRequestMethod("GET");
            httpConn.connect();
            if (httpConn.getResponseCode() != HttpURLConnection.HTTP_OK) {
                log.error("message: HTTP状态码{}", httpConn.getResponseCode());
                return;
            }

            // 打开onlyoffice中的缓存文件
            inputStream = httpConn.getInputStream();
            if (null == inputStream) {
                log.error("message: Stream is null");
                return;
            }

            // 生成文件在服务器上的绝对路径
            String filePath = this.generateFilepath(payload);
            if (StringUtils.isBlank(filePath)) {
                log.error("message: 文件路径在服务器上不存在");
                return;
            }

            // 将缓存文件中的内容读出并保存到本地文件中
            outputStream = new FileOutputStream(filePath);
            byte[] buffer = new byte[1024];  // 缓冲区
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        } catch (Exception e) {
            log.info("message: {}    exception: {}", e.getMessage(), Arrays.toString(e.getStackTrace()));
        } finally {
            try {
                // 关闭流
                if (inputStream != null) inputStream.close();
                if (outputStream != null) outputStream.close();
            } catch (IOException e) {
                log.info("message: {}    exception: {}", "关闭文件失败, " + e.getMessage(), Arrays.toString(e.getStackTrace()));
            }
        }
    }

    /**
     * 创建文件在服务器上的绝对路径
     * @param payload onlyoffice服务器发送过来的参数
     * @return 文件绝对路径
     */
    private String generateFilepath(Map<String, Object> payload) {
        // 文件key，用key作为文件名称，实际生产环境中应该用key查找对应的文件名称
        String key = payload.getOrDefault("key", "").toString();
        if (StringUtils.isBlank(key)) {
            return "";
        }

        // 文件类型
        String fileType = payload.getOrDefault("filetype", "").toString();
        if (StringUtils.isBlank(fileType)) {
            return "";
        }
        return StringUtils.stripEnd(this.documentDir, "/") + "/" + key + "." + fileType;
    }
}
